import os
import network as network_module
import thread as thread_module
import image as image_module
import sys
from ctypes import POINTER, WinDLL, Structure, sizeof, byref
from ctypes.wintypes import BOOL, SHORT, WCHAR, UINT, ULONG, DWORD, HANDLE
import win32console
import time


def console_full_screen():
    h = win32console.GetStdHandle(win32console.STD_OUTPUT_HANDLE)
    h.SetConsoleDisplayMode(win32console.CONSOLE_FULLSCREEN_MODE, win32console.PyCOORDType(0, 0))


def console_windowed_screen():
    h = win32console.GetStdHandle(win32console.STD_OUTPUT_HANDLE)
    h.SetConsoleDisplayMode(win32console.CONSOLE_WINDOWED_MODE, win32console.PyCOORDType(0, 0))


LF_FACESIZE = 32        # 设置控制台字体
STD_OUTPUT_HANDLE = -11


class COORD(Structure):
    _fields_ = [
        ("X", SHORT),
        ("Y", SHORT),
    ]


class CONSOLE_FONT_INFOEX(Structure):
    _fields_ = [
        ("cbSize", ULONG),
        ("nFont", DWORD),
        ("dwFontSize", COORD),
        ("FontFamily", UINT),
        ("FontWeight", UINT),
        ("FaceName", WCHAR * LF_FACESIZE)
    ]


kernel32_dll = WinDLL("kernel32.dll")

get_last_error_func = kernel32_dll.GetLastError
get_last_error_func.argtypes = []
get_last_error_func.restype = DWORD

get_std_handle_func = kernel32_dll.GetStdHandle
get_std_handle_func.argtypes = [DWORD]
get_std_handle_func.restype = HANDLE

get_current_console_font_ex_func = kernel32_dll.GetCurrentConsoleFontEx
get_current_console_font_ex_func.argtypes = [HANDLE, BOOL, POINTER(CONSOLE_FONT_INFOEX)]
get_current_console_font_ex_func.restype = BOOL

set_current_console_font_ex_func = kernel32_dll.SetCurrentConsoleFontEx
set_current_console_font_ex_func.argtypes = [HANDLE, BOOL, POINTER(CONSOLE_FONT_INFOEX)]
set_current_console_font_ex_func.restype = BOOL


def change_console_font_size(size):
    # Get stdout handle
    stdout = get_std_handle_func(STD_OUTPUT_HANDLE)
    # Get current font characteristics
    font = CONSOLE_FONT_INFOEX()
    font.cbSize = sizeof(CONSOLE_FONT_INFOEX)
    res = get_current_console_font_ex_func(stdout, False, byref(font))
    # Display font information

    height = size
    # Alter font height
    font.dwFontSize.X = 10  # Changing X has no effect (at least on my machine)
    font.dwFontSize.Y = height
    # Apply changes
    res = set_current_console_font_ex_func(stdout, False, byref(font))
    # Get current font characteristics again and display font size
    res = get_current_console_font_ex_func(stdout, False, byref(font))


class Lib:
    def __init__(self):
        self.network = network_module
        self.thread = thread_module
        self.image = image_module


lib = Lib()


def home_page(_string=''):
    # _string 前置消息，用于报错
    os.system('cls')
    print(_string)

    print('*' * 80)
    print(f'*{" " * 78}*')
    print(f'*{" " * 29}Welcome to IedAnime!{" " * 29}*')
    print(f'*{" " * 78}*')
    print(f'*{" " * 78}*')
    print(f'*{" " * 8}[1] Search by Keyword{" " * 15}[2] Search by genres{" " * 14}*')
    print(f'*{" " * 8}[3] Random anime{" " * 20}[4] Popular anime{" " * 17}*')
    print(f'*{" " * 8}[5] Latest episode{" " * 18}[6] Ongoing anime{" " * 17}*')
    print(f'*{" " * 8}[7] Latest anime{" " * 20}[8] Winter 2021{" " * 19}*')

    print(f'*{" " * 78}*')
    print(f'*{" " * 8}[a] Download manager{" " * 16}[b] User Center{" " * 19}*')
    print(f'*{" " * 8}[c] Message{" " * 25}[d] About IedAnime{" " * 16}*')

    print(f'*{" " * 78}*')
    print(f'*{" " * 8}Use command "/exit" to exit{" " * 43}*')
    print(f'*{" " * 78}*')
    print('*' * 80)

    print('[*] Enter the index or the command to start the next step')
    __input__ = input('>? ')

    if __input__ == '1':
        search_by_keyword()

    elif __input__.replace(' ', '') == '/exit':
        print('\nGoodbye!\n')
        exit(0)
        
def view_anime(view_url):
    network = lib.network.View(view_url)
    anime_info = network.get_anime_info()
    # {
    #     'name': name,
    #     'description': description,
    #     'genres': genres,
    #     'rating': rating,
    #     'status': status,
    #     'type': type,
    #     'first_aired': first_aired,
    #     'episodes_info': list(zip(episodes_name, episodes_release_time, episodes_href)),  # 顺序从集数大到小
    #     'cover': cover
    #  }
    name = anime_info['name']
    description = anime_info['description']
    genres = anime_info['genres']
    rating = anime_info['rating']
    status = anime_info['status']
    type = anime_info['type']
    first_aired = anime_info['first_aired']
    episodes_info = anime_info['episodes_info'][::-1]

    os.system('cls')
    print('*' * 80)
    print(f'*{" " * 78}*')
    print(f'*{" " * 29}Now you are in <View>{" " * 28}*')
    print(f'*{" " * 78}*')
    print(
        f'*{" " * int((80 - 2 - 7 - len(name)) / 2)}Anime: {name}{" " * (80 - int((80 - 2 - 7 - len(name)) / 2) - 2 - 7 - len(name))}*')
    print(f'*{" " * 78}*')
    print(f'*{" " * 8}Use command "/exit" to exit{" " * 43}*')
    print(f'*{" " * 8}Use command "/home" to back to home page{" " * 30}*')
    print(f'*{" " * 8}Use command "/download <index>" to download a certain episode{" " * 9}*')
    print(f'*{" " * 8}Use command "/download <index1>, <index2>" to download episodes{" " * 7}*')
    print(f'*{" " * 78}*')
    print('*' * 80)

    # - - -

    print('')
    print('*' * 80)
    print(f'*{" " * 78}*')
    print(f'*{" " * 8}Anime: {name}{" " * (80 -8 - 2 - 7 - len(name))}*')
    print(f'*{" " * 8}Genres: {genres}{" " * (80 -8 - 2 - 8 - len(genres))}*')
    print(f'*{" " * 8}Rating: {rating}{" " * (80 -8 - 2 - 8 - len(rating))}*')
    print(f'*{" " * 8}Status: {status}{" " * (80 -8 - 2 - 8 - len(status))}*')
    print(f'*{" " * 8}type: {type}{" " * (80 -8 - 2 - 6 - len(type))}*')
    print(f'*{" " * 8}First aired: {first_aired}{" " * (80 -8 - 2 - 13 - len(first_aired))}*')
    print(f'*{" " * 8}Description: {" " * 57}*')

    for sentence in description:
        print(f'*{" " * 12}{sentence}{" " * (80-2-12-len(sentence))}*')

    print(f'*{" " * 78}*')
    print('*' * 80)

    # - - -

    print('')
    print('*' * 80)
    print(f'*{" " * 78}*')
    print(f'*{" " * 35}Episodes{" " * 35}*')
    print(f'*{" " * 78}*')
    for index in range(len(episodes_info)):
        episode_info = episodes_info[index]
        print(f'*{" " * 8}[{index}] {episode_info[0]}{" " * (80-2-8-2-1-len(str(index)+episode_info[0]))}*')
        print(f'*{" " * 15}{episode_info[1]}{" " * (80-2-15-len(episode_info[1]))}*')
        print(f'*{" " * 78}*')

    print(f'*{" " * 78}*')
    print('*' * 80)

    # - - -

    print('')
    print('\nEnter your command:')
    __input__ = input('>? ')

    if __input__.replace(' ', '') == '/exit':
        print('\nGoodbye!\n')
        exit(0)

    elif __input__.replace(' ', '') == '/home':
        home_page()
        return 0

    elif __input__[:9] == '/download':      # /download 1, 9, 24
        __input__ = __input__[10:].replace(' ', '').replace('，', '')      # 1,9,24
        if ',' in __input__:
            indexes = [int(index) for index in __input__.split(',')]
        else:
            indexes = [int(__input__)]

        for index in indexes:
            # lib.thread.DownloaderManager.add_downloader(
                # lib.network.Downloader(episodes_info[index][2], 256, f"{name}_{episodes_info[index][0]}.mp4")
            # )
            lib.network.Downloader(episodes_info[index][2], 512, f"{name}_{episodes_info[index][0]}.mp4").start()
            
        input('Press <ENTER> to confirm...\n>? ')
        home_page()

    else:
        home_page(
            '*' * 80 + '\n*' + ' ' * 78 + '*' + '\n*' + '      Feedback from function <view_anime>:' + ' ' * 36 + '*' +
            '\n*' + ' ' * 34 + 'invalid command' + ' ' * 29 + '*' + '\n*' + ' ' * 78 + '*\n' + '*' * 80
        )

def search_by_keyword_show_page(anime_list, page, keyword):       # page 从 0 开始
    #  [{
    #     'name': anime_info_read_dict['name'],
    #     'seo_name': anime_info_read_dict['seo_name'],
    #     'update_to': anime_info_read_dict.episodes[0]['episode_name'],
    #     'img': f'https://www.animefreak.tv/meta/anime/'
    #            f'{anime_info_read_dict["name"]}/{anime_info_read_dict["seo_name"]}.jpg'
    #     }, ...
    #  ]

    os.system('cls')
    print('*' * 80)
    print(f'*{" " * 78}*')
    print(f'*{" " * 22}Now you are in <Search by Keyword>{" " * 22}*')
    print(f'*{" " * 78}*')
    print(f'*{" " * int((80-2-9-len(keyword))/2)}Keyword: {keyword}{" "*(80 - int((80-2-9-len(keyword))/2) - 2 - 9 - len(keyword))}*')
    print(f'*{" " * 78}*')
    print(f'*{" " * 8}Use command "/exit" to exit{" " * 43}*')
    print(f'*{" " * 8}Use command "/home" to back to home page{" " * 30}*')
    print(f'*{" " * 8}Use command "/page <page num>" to jump to certain page{" " * 16}*')
    print(f'*{" " * 8}Use command "/view <index>" to view a certain anime{" " * 19}*')
    print(f'*{" " * 8}Use command "/cover <index>" to view a certain anime{" " * 18}*')
    print(f'*{" " * 78}*')
    print('*' * 80)

    print('\n')
    print('*' * 80)
    print(f'*{" " * 78}*')
    print(f'*{" " * 31}Search    Result{" " * 31}*')
    print(f'*{" " * 78}*')
    for item in anime_list[page*6: page*6+6]:
        name = item['name']
        index = str(anime_list.index(item))
        print(f'*{" " * 78}*')
        print(f'*{" " * 8}[{index}] {name}{" " * (80-8-2-3-len(name)-len(index))}*')

    print(f'*{" " * 78}*')
    print(f'*{" " * 78}*')
    print(f'*{" " * int((80-2-6-len(str(page+1)))/2)}Page: {page+1}{" " * (80-int((80-2-6-len(str(page+1)))/2)-2-6-len(str(page+1)))}*')
    print(f'*{" " * 78}*')
    print('*' * 80)

    print('\nEnter your command:')
    __input__ = input('>? ')

    if __input__.replace(' ', '') == '/exit':
        print('\nGoodbye!\n')
        exit(0)

    elif __input__.replace(' ', '') == '/home':
        home_page()
        return 0

    elif __input__[:5] == '/page':
        __input__ = __input__[6:]
        search_by_keyword_show_page(anime_list, int(__input__)-1, keyword)

    elif __input__[:5] == '/view':
        __input__ = int(__input__[6:])
        view_anime('https://www.animefreak.tv/watch/' + anime_list[__input__]['seo_name'])

    elif __input__[:6] == '/cover':
        __input__ = int(__input__[7:])
        print('[*] Loading...')
        print('[*] Target image url: %s' % anime_list[__input__]['img'])
        print('[*] Please wait patiently before the cover displays completely')
        time.sleep(1)
        while 1:
            try:
                im = lib.image.load_colored_image(url=anime_list[__input__]['img'])
                break
            except:
                pass

        change_console_font_size(5)
        console_windowed_screen()
        console_full_screen()
        sys.stdout.write('STDOUT TEST\r')
        lib.image.print_colored_image(im)
        input('>? ')
        change_console_font_size(16)
        search_by_keyword_show_page(anime_list, page, keyword)
        
    else:
        home_page(
            '*' * 80 + '\n*' + ' '*78 + '*' + '\n*' + '      Feedback from function <search_by_keyword_show_page>:' + ' '*19 + '*' +
            '\n*' + ' '*34 + 'invalid command' + ' '*29 + '*' + '\n*' + ' '*78 + '*\n' + '*' * 80
        )
        


def search_by_keyword():
    os.system('cls')
    print('*' * 80)
    print(f'*{" " * 78}*')
    print(f'*{" " * 22}Now you are in <Search by Keyword>{" " * 22}*')
    print(f'*{" " * 78}*')
    print(f'*{" " * 8}Use command "/exit" to exit{" " * 43}*')
    print(f'*{" " * 8}Use command "/home" to back to home page{" " * 30}*')
    print(f'*{" " * 8}Use command "/search <keyword>" to search by keyword{" " * 18}*')
    print(f'*{" " * 78}*')
    print('*'*80)

    print('\nEnter your command or keyword:')
    __input__ = input('>? ')
    if __input__.replace(' ', '') == '/exit':
        print('\nGoodbye!\n')
        exit(0)

    elif __input__.replace(' ', '') == '/home':
        home_page()
        return 0

    elif __input__[:7] == '/search':
        __input__ = __input__[8:]       # 只截取了有效部分
        while len(__input__) > 60:
            print('\n[!] ERROR: keyword too long')
            print('Enter your keyword:')
            __input__ = input('>? ')
        network = lib.network.SearchByKeyword(__input__)
        anime_list = network.anime_info_complied_list       # anime info
        #  [{
        #     'name': anime_info_read_dict['name'],
        #     'seo_name': anime_info_read_dict['seo_name'],
        #     'update_to': anime_info_read_dict.episodes[0]['episode_name'],
        #     'img': f'https://www.animefreak.tv/meta/anime/'
        #            f'{anime_info_read_dict["name"]}/{anime_info_read_dict["seo_name"]}.jpg'
        #     }, ...
        #  ]
        search_by_keyword_show_page(anime_list, 0, __input__)

    else:
        home_page(
            '*' * 80 + '\n*' + ' '*78 + '*' + '\n*' + '      Feedback from function <search_by_word>:' + ' '*32 + '*' +
            '\n*' + ' '*34 + 'invalid command' + ' '*29 + '*' + '\n*' + ' '*78 + '*\n' + '*' * 80
        )


if __name__ == '__main__':
    console_full_screen()
    change_console_font_size(16)
    home_page()
